home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Applications / Alpha.5.96 folder / Tcl / UserCode / MacPerl.tcl < prev    next >
Encoding:
Text File  |  1994-09-21  |  39.3 KB  |  1,279 lines  |  [TEXT/ALFA]

  1. #############################################################################
  2. # MacPerl.tcl
  3. # -----------
  4. #
  5. # This is a set of routines that allow Alpha to act as a front end for the
  6. # standalone MacPerl application and that allow Perl scripts to be used as 
  7. # text filters in Alpha.  These functions are accessed through a special
  8. # MacPerl menu.
  9. #
  10. # To install the menu, choose "MacPerl" from the "Utils/Install" menu.
  11. #
  12. # The features of this package are explained in the file "MacPerl Help",
  13. # accessible from the Help menu.
  14. #
  15. #############################################################################
  16. #
  17. # If you don't already have MacPerl, it's available by anonymous ftp from
  18. # the umich site
  19. #
  20. #   mac.archive.umich.edu    [141.211.165.34]    mac/development/languages                            (4)
  21. #
  22. # and its mirrors.  Also, MacPerl's home site is 
  23. #
  24. #   ftp.switch.ch            [130.59.1.40]        software/mac/src/mpw_c
  25. #
  26. # MacPerl was written (ported to the Mac) by 
  27. #        Matthias Neeracher <neeri@iis.ee.ethz.ch> , and
  28. #        Tim Endres <time@ice.com>.
  29. #
  30. #############################################################################
  31. # Authors: W. Thomas Pollard (pollard@chem.columbia.edu)
  32. #          Martijn Koster (m.koster@nexor.co.uk)
  33. #
  34. # Version History:
  35. #
  36. # 1.5  9/94  -  MacPerl menu rearranged somewhat.
  37. #               Explicit "Get Output Window" command added to menu.
  38. #               Reading "#!" line for args is incompatible w/ standard,
  39. #                   so it's been dropped.
  40. #               Only scan the first 40 output lines for error messages (faster)
  41. #                "wrapFilterScript" no longer opens STDIN
  42. #               Text filters may now use command-line args
  43. #               STDIN for text filters passed as explicit cmd-line arg 
  44. # 1.4  9/94  -  The "#!" line of every script is read for command-line args,
  45. #                    which are passed explicitly to MacPerl with the script.
  46. #                "PromptForArgs" menu flag added.
  47. #                "perlCmdlineArgs" modeVar holds default command-line args.
  48. #                Scripts are sent using custom "perlDoScript2" proc, which
  49. #                    allows passing of explicit command-line args.
  50. # 1.3  9/94  -  When any script generates a compilation error, the file 
  51. #                    containing the script is brought up with the offending 
  52. #                    line highlighted; all error output is also written to
  53. #                    a "Perl Error Messages" window.
  54. #                'repeatLastFilter' runs again the last text-filter script used.
  55. #                'perlLastFilter' modeVar holds pathname of last filter.
  56. #                Menu flags now mirrored as modeVars, so they can be saved and
  57. #                    restored between sessions.
  58. #                Minor bug fixes.
  59. # 1.2  8/94  -  'retrieveOutput' and 'autoSwitch' flags added.
  60. #                'openInMacperl' added.
  61. #                MacPerl output window now closed before new scripts are sent.
  62. #                Filters now abort if there are compilation errors, and
  63. #                MacPerl diagnostic output retrieved and displayed in Alpha.
  64. # 1.1  8/94  -  'quitMacperl' added.
  65. #               perl-mode file-marking updated for Alpha 5.90
  66. #               Simplified installation via 'loadMacperl'(Pete Keleher). 
  67. # 1.0  7/94  -  perl-mode setup updated for Alpha 5.85:
  68. #                    keyword colorization supported
  69. #                    custom file-marking added
  70. #               #! lines in filter scripts now handled correctly 
  71. #               Workarounds installed for AppleEvent bug in MacPerl 4.1.3
  72. # 0.9  3/94  -  perl-mode stuff added, and
  73. #               highlighted 'Perl commands' file (man page) prepared
  74. #               minor bug fixes, too
  75. # 0.8  3/94  -  flags are now check-marked
  76. # 0.7  3/94  -  nested Text Filters folder now supported
  77. #               menu format modified somewhat
  78. # 0.6  3/94  -  'applyToBuffer' flag added
  79. #               scripts in Alpha buffers can now be used as filters 
  80. # 0.5  2/94  -  'filters', 'open special' submenu added
  81. #               'overwrite' flag added
  82. # 0.2  1/94  -  menu support added (MK)
  83. #               'execute selection', 'execute buffer' commands added
  84. # 0.1  9/93  -  text filter functionality created (WTP)
  85. #                  
  86. #   Comments, suggestions, bug reports, etc., should be directed to 
  87. #   Tom Pollard (pollard@chem.columbia.edu).
  88. #
  89. #############################################################################
  90. #  Default settings for the Perl menu flags  
  91. #
  92. set perlGetOutput 1
  93. set perlAutoSwitch 1
  94. set perlOverwrite 0
  95. set perlUsebuffer 1
  96. set perlPromptArgs 0
  97.  
  98. set perlPrevScript {*startup*}
  99. set perlCmdlineArgs {}
  100.  
  101. # Make duplicate copies of these variables as modeVars, taking responsibility
  102. # for keeping the two sets consistent (argh!)
  103.  
  104. newModeVar Perl perlGetOutput $perlGetOutput 1
  105. newModeVar Perl perlAutoSwitch $perlAutoSwitch 1
  106. newModeVar Perl perlOverwrite $perlOverwrite 1
  107. newModeVar Perl perlUsebuffer $perlUsebuffer 1
  108. newModeVar Perl perlPromptArgs $perlPromptArgs 1
  109.  
  110. newModeVar Perl perlLastFilter $perlPrevScript 0
  111. newModeVar Perl perlCmdlineArgs $perlCmdlineArgs 0
  112.  
  113. #############################################################################
  114. #  To install the MacPerl package, the user is prompted to locate his
  115. #  MacPerl application.  This information (necessary for building the MacPerl
  116. #  menu) recorded in UserStartup.tcl, along with commands that will load
  117. #  MacPerl mode automatically in the future.
  118. #
  119. proc loadMacPerl {} {
  120.     global macperlPath mode modeMenus HOME
  121.     set name [lindex [winNames -f] 0]
  122.         
  123.     if {[askyesno "Install the MacPerl menu?"] == "yes"} {
  124.         set f [getfile {Where is your MacPerl application?"}]
  125.         
  126.         # modify UserStartup.tcl so that Perl menu loads automatically
  127.         addUserLine "\r\# The next three lines enable the MacPerl menu."
  128.         addUserLine "set macperlPath \"$f\""
  129.         addUserLine "source \"\$HOME:Tcl:UserCode:MacPerl.tcl\""
  130.         addUserLine "enableMenuItem -m install MacPerl 0"
  131.         
  132.         # enable Perl menu for this session
  133.         set macperlPath $f
  134.         
  135.         if {[askyesno "Display MacPerl menu in Text mode?"] == "yes"} {
  136.             addUserLine "lappend modeMenus(Text) {perlMenu}"
  137.             lappend modeMenus(Text) {perlMenu}
  138.         }
  139.         
  140.         if {[askyesno "Copy sample Text Filters to your MacPerl folder?"] == "yes"} {
  141.             if {[catch {cpdir "$HOME:Tcl:UserCode:Text Filters" [macperlFolder]}]} {
  142.                 alertnote "Text Filters folder couldn't be copied"
  143.             } else {
  144.                 alertnote "Text Filters folder was successfully copied" 
  145.             }
  146.         }
  147.         
  148.         rebuildPerlMenu
  149.         enableMenuItem -m install "MacPerl" 0
  150.  
  151.         # reset the mode, so that Perl menu is inserted if required
  152.         set currentMode $mode
  153.         changeMode none
  154.         changeMode $currentMode
  155.     }
  156. }
  157.  
  158. #############################################################################
  159. #  Return paths to standard files, based on the path to MacPerl:
  160. #
  161. proc macperlFolder {} {
  162.    global macperlPath
  163.    regexp {(.*):([^:]*)} $macperlPath pathname dirname filename
  164.    return ${dirname}:
  165. }
  166.  
  167. proc stdinPath {} {
  168.    return [macperlFolder]STDIN
  169. }
  170.  
  171. proc stdoutPath {} {
  172.    return [macperlFolder]STDOUT
  173. }
  174.  
  175. proc scriptPath {} {
  176.    return [macperlFolder]SCRIPT
  177. }
  178.  
  179. proc scriptFolder {} {
  180.    return "[macperlFolder]Text Filters:"
  181. }
  182.  
  183. #############################################################################
  184. #  This is a generally useful proc that builds a hierarchical menu 
  185. #  from the files in a given folder and all subfolders.  As the menu is
  186. #  built, the pathnames of the various files are saved in the array
  187. #  indicated  by $filePaths.  The index of the file's path in this array
  188. #  is formed by concatenating the submenu name and filename, allowing the
  189. #  pathname to be retrieved by the procedure $proc when the menu item is
  190. #  selected.
  191. #
  192. proc buildSubMenu {folder name proc filePaths} {
  193.     global $filePaths
  194.     if {$name == 0} {
  195.         set name [file tail [file dirname $folder]]
  196.     }
  197.     if {$proc == 0} {
  198.         set pproc ""
  199.     } else {
  200.         set pproc "-p $proc"
  201.     }
  202.     set menu {}
  203.     set filenames [glob -nocomplain  $folder\*]
  204.     if {[llength $filenames] > 0} {
  205.        foreach m $filenames {
  206.           if {[file isdirectory $m]} {
  207.               lappend menu [buildSubMenu ${m}: 0 $proc $filePaths] 
  208.           } elseif {[file isfile $m]} {
  209.               set fname [file tail $m]
  210.               lappend menu $fname
  211.               set ${filePaths}($name:$fname) $m
  212.           }
  213.          }
  214.     }
  215.     return [concat {menu -m -n} [list $name] $pproc [list $menu]]
  216. }
  217.  
  218. #############################################################################
  219. #  Build a submenu of "preattached" Perl filters using the names of the 
  220. #  scripts in the Text Filters directory
  221. #
  222. proc perlFilterMenu {} {
  223.     global perlFilterPath
  224.     set scriptDir [scriptFolder]
  225.     if {![file exists $scriptDir]} {
  226.        cd [macperlFolder]
  227.        mkdir {Text Filters}
  228.        alertnote "Creating new \"Text Filters\" folder in MacPerl folder" 
  229.        cd
  230.     }
  231.     return [buildSubMenu $scriptDir TextFilters textFiltersProc perlFilterPath]
  232. }
  233.  
  234. #############################################################################
  235. #  Build the perl menu
  236. #
  237. proc rebuildPerlMenu {} {
  238.     global perlMenu perlOverwrite perlUsebuffer perlGetOutput perlAutoSwitch
  239.     global perlPrevScript perlPromptArgs
  240.             
  241.     set perlMenu "•132"
  242.     menu -n $perlMenu [ concat {
  243.         "macperl"
  244.         {menu -m -n "tellMacperl..." -p perlTellProc {
  245.            "Open This File"
  246.            "Get Output Window"
  247.            "Quit"
  248.            }
  249.         } 
  250.         "(-"
  251.         "runTheSelection"
  252.         "runTheBuffer"
  253.         "runAFile"
  254.         "(-"
  255.         } [list [perlFilterMenu]] {
  256.         {menu -n OtherTextFilters {
  257.            "selectABuffer"
  258.            "selectAFile"
  259.            }
  260.         } 
  261.         "repeatLastFilter"
  262.         {menu -m -n openSpecial -p perlOpenFile {
  263.            "STDIN"
  264.            "STDOUT"
  265.            "SCRIPT"
  266.            }
  267.         } 
  268.         "(-"
  269.         "retrieveOutput"
  270.         "autoSwitch"
  271.         "promptForArgs"
  272.         "applyToBuffer"
  273.         "overwriteSelection"
  274.         "(-"
  275.         "rebuildPerlMenu"
  276.         } ]
  277.  
  278.     markMenuItem $perlMenu retrieveOutput $perlGetOutput
  279.     markMenuItem $perlMenu autoSwitch $perlAutoSwitch
  280.     markMenuItem $perlMenu overwriteSelection $perlOverwrite
  281.     markMenuItem $perlMenu applyToBuffer $perlUsebuffer
  282.     markMenuItem $perlMenu promptForArgs $perlPromptArgs
  283.     if {$perlPrevScript == {} || $perlPrevScript == {*startup*}} {
  284.         enableMenuItem $perlMenu repeatLastFilter 0
  285.     }
  286. }
  287.  
  288. if ([info exists macperlPath]) {
  289.     rebuildPerlMenu
  290. }
  291.  
  292. # Keep global vars and modeVars consistent.
  293. #
  294. trace variable PerlmodeVars(perlOverwrite) w shadowPerl
  295. trace variable PerlmodeVars(perlUsebuffer) w shadowPerl
  296. trace variable PerlmodeVars(perlGetOutput) w shadowPerl
  297. trace variable PerlmodeVars(perlAutoSwitch) w shadowPerl
  298. trace variable PerlmodeVars(perlPromptArgs) w shadowPerl
  299. trace variable PerlmodeVars(perlLastFilter) w shadowPerl
  300. trace variable PerlmodeVars(perlCmdlineArgs) w shadowPerl
  301.  
  302. # ShadowPerl sets the global vars when the mode vars are modified and
  303. # keeps the menu checkmarked correctly.
  304. #
  305. proc shadowPerl {name1 name2 op} {
  306.     global perlMenu perlOverwrite perlUsebuffer perlGetOutput perlAutoSwitch
  307.     global perlPromptArgs perlPrevScript perlCmdlineArgs 
  308.     global PerlmodeVars
  309.     if {$name1 == "PerlmodeVars" && $op == "w"} {
  310.         switch $name2 {
  311.             "perlOverwrite"    {
  312.                 set perlOverwrite $PerlmodeVars(perlOverwrite)
  313.                 markMenuItem $perlMenu overwriteSelection $perlOverwrite
  314.              }
  315.             "perlUsebuffer"    {
  316.                 set perlUsebuffer $PerlmodeVars(perlUsebuffer)
  317.                 markMenuItem $perlMenu applyToBuffer $perlUsebuffer
  318.              }
  319.             "perlGetOutput"    {
  320.                 set perlGetOutput $PerlmodeVars(perlGetOutput)
  321.                 markMenuItem $perlMenu retrieveOutput $perlGetOutput 
  322.             }
  323.             "perlAutoSwitch" {    
  324.                 set perlAutoSwitch $PerlmodeVars(perlAutoSwitch)
  325.                 markMenuItem $perlMenu autoSwitch $perlAutoSwitch 
  326.             }
  327.             "perlPromptArgs" {    
  328.                 set perlPromptArgs $PerlmodeVars(perlPromptArgs)
  329.                 markMenuItem $perlMenu promptForArgs $perlPromptArgs 
  330.             }
  331.             "perlCmdlineArgs" {    
  332.                 set perlCmdlineArgs $PerlmodeVars(perlCmdlineArgs)
  333.             }
  334.             "perlLastFilter" {    
  335.                 # Don't allow perlPrevScript to be changed from the flags menu
  336.                 if {$perlPrevScript == "*startup*"} {
  337.                     set perlPrevScript $PerlmodeVars(perlLastFilter)
  338.                     enableMenuItem $perlMenu repeatLastFilter 1
  339.                 } else {
  340.                     set PerlmodeVars(perlLastFilter) $perlPrevScript 
  341.                 }
  342.             }
  343.             default {
  344.                 return
  345.             }
  346.         }
  347.     }
  348. }
  349.  
  350. #############################################################################
  351. # Menu commands
  352. #############################################################################
  353.  
  354. ############################################################################
  355. # Toggle the perl menu flags
  356. #
  357. proc retrieveOutput {} {
  358.     global perlMenu PerlmodeVars perlGetOutput modifiedModeVars
  359.     lappend modifiedModeVars perlGetOutput
  360.     if {$perlGetOutput} then {
  361.         set PerlmodeVars(perlGetOutput) 0
  362.     } else {
  363.         set PerlmodeVars(perlGetOutput) 1
  364.     }
  365. }
  366.  
  367. proc autoSwitch {} {
  368.     global perlMenu PerlmodeVars perlAutoSwitch modifiedModeVars
  369.     lappend modifiedModeVars perlAutoSwitch
  370.     if {$perlAutoSwitch} then {
  371.         set PerlmodeVars(perlAutoSwitch) 0
  372.     } else {
  373.         set PerlmodeVars(perlAutoSwitch) 1
  374.     }
  375. }
  376.  
  377. proc overwriteSelection {} {
  378.     global perlMenu perlOverwrite PerlmodeVars modifiedModeVars
  379.     lappend modifiedModeVars perlOverwrite
  380.     if {$perlOverwrite} then {
  381.         set PerlmodeVars(perlOverwrite) 0
  382.     } else {
  383.         set PerlmodeVars(perlOverwrite) 1
  384.     }
  385. }
  386.  
  387. proc applyToBuffer {} {
  388.     global perlMenu perlUsebuffer PerlmodeVars modifiedModeVars
  389.     lappend modifiedModeVars perlUsebuffer
  390.     if {$perlUsebuffer} then {
  391.            set PerlmodeVars(perlUsebuffer) 0
  392.     } else {
  393.            set PerlmodeVars(perlUsebuffer) 1
  394.     }
  395. }
  396.  
  397. proc promptForArgs {} {
  398.     global perlMenu perlPromptArgs PerlmodeVars modifiedModeVars
  399.     lappend modifiedModeVars perlPromptArgs
  400.     if {$perlPromptArgs} then {
  401.            set PerlmodeVars(perlPromptArgs) 0
  402.     } else {
  403.            set PerlmodeVars(perlPromptArgs) 1
  404.     }
  405. }
  406.  
  407. #############################################################################
  408. # Switch to MacPerl:
  409. proc macperl {} {
  410.     global macperlPath
  411.     set name [checkRunning MacPerl McPL macperlPath]
  412.     if {[string length $name]} {
  413.         switchTo "MacPerl"
  414.     } else {
  415.         alertnote "Couldn't run MacPerl"
  416.     }
  417. }
  418.  
  419. #############################################################################
  420. # Interact with MacPerl in some other way besides executing a script
  421. #
  422. proc perlTellProc {menu name} {
  423.     if {$name == "Open This File"} {
  424.         openInMacperl
  425.     } elseif {$name == "Get Output Window"} {
  426.         openPerlOutput
  427.     } elseif {$name == "Quit"} {
  428.         quitMacperl
  429.     }
  430. }
  431.  
  432. #############################################################################
  433. # Open the current file under MacPerl.  This is useful if you want to save it 
  434. # as a droplet or runtime script.
  435. #
  436. proc openInMacperl {} {
  437.     global macperlPath
  438.     set name [checkRunning MacPerl McPL macperlPath]
  439.     if {![string length $name]} {
  440.         alertnote "Couldn't run MacPerl"
  441.     }
  442.  
  443.     if {[winInfo dirty]} {
  444.         case [askyesno -c "Save '[lindex [winNames] 0]'?"] in {
  445.             "yes" {save}
  446.             "no" {}
  447.             "cancel" {return}
  448.         }
  449.     }
  450.     switchTo $name
  451.     sendOpenEvent -n $name [lindex [winNames -f] 0]
  452. }
  453.  
  454. #############################################################################
  455. # Quit a running MacPerl app:
  456. proc quitMacperl {} {
  457.     foreach proc [processes] {
  458.         set sig [lindex $proc 1]
  459.         if {$sig == "McPL"} {
  460.             sendQuitEvent [lindex $proc 0]
  461.             # switchTo is necessary to keep MacPerl from blinking
  462.             switchTo [lindex $proc 0]    
  463.         }
  464.     }
  465. }
  466.  
  467. #############################################################################
  468. # Run the selection as a MacPerl script:
  469. # (No special arrangements are made to provide input or capture the output)
  470. proc runTheSelection {} {
  471.     global scriptFile scriptStart
  472.     set scriptFile [lindex [winNames -f] 0]
  473.     set scriptStart [lindex [posToRowCol [getPos]] 0]
  474.     perlExecuteScript [getSelect]
  475. }
  476.  
  477. proc runTheBuffer {} {
  478.     global scriptFile scriptStart
  479.     set scriptFile [lindex [winNames -f] 0]
  480.     set scriptStart 1
  481.     perlExecuteScript [getText 0 [maxPos]]
  482. }
  483.  
  484. proc runAFile {} {
  485.     global scriptFile scriptStart
  486.     if {! [catch {getfile "Select a Perl script"} path]} {
  487.         set scriptFile $path
  488.         set scriptStart 1
  489.         perlExecuteFile $path
  490.     }
  491. }
  492.  
  493. #############################################################################
  494. # Run a preattached Perl text-filter script selected from the menu:
  495. #
  496. proc textFiltersProc {menu name} {
  497.     global perlFilterPath scriptFile scriptStart
  498.     
  499.     perlFileAsFilter $perlFilterPath($menu:$name)
  500. }
  501.  
  502. #############################################################################
  503. # Reuse the previous (buffer or file) filter:
  504. #
  505. proc repeatLastFilter {} {
  506.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  507.     if {$perlPrevScript != {}} {
  508.         set stype [lindex $perlPrevScript 0]
  509.         set name [lindex $perlPrevScript 1]
  510.         if {$stype == "file"} {
  511.             perlFileAsFilter $name
  512.         } elseif {$stype == "buffer"} {
  513.             perlBufferAsFilter $name
  514.         } else {
  515.             message "Bogus filter name : \"$perlPrevScript\""
  516.             set perlPrevScript {}
  517.             set PerlmodeVars(perlLastFilter) $perlPrevScript 
  518.             enableMenuItem $perlMenu repeatLastFilter 0
  519.         }
  520.     }
  521. }
  522.  
  523. #############################################################################
  524. # Ask for a file containing a Perl script to use as a filter:
  525. #
  526. proc selectAFile {} {
  527.     global scriptFile scriptStart perlPrevScript
  528.     if {! [catch {getfile "Select a MacPerl script"} path]} {
  529.         perlFileAsFilter $path
  530.     }
  531. }
  532.  
  533. #############################################################################
  534. # Ask for an Alpha buffer containing a Perl script to use as a filter:
  535. #
  536. proc selectABuffer {} {
  537.     global scriptFile scriptStart perlPrevScript
  538.     
  539.     set windows [winNames]
  540.     set current [lindex $windows 0]
  541.     if {[llength $windows] > 1} {
  542.         set name [listpick [lsort $windows]]
  543.         if {[string length $name]} {
  544.             # get the full name of the chosen window
  545.             set wname [lindex [winNames -f] [lsearch -exact $windows $name]]
  546.             perlBufferAsFilter $wname
  547.            }
  548.     }
  549. }
  550.  
  551. #############################################################################
  552. # Open a file from the MacPerl application folder - used by "Open Special"
  553. #
  554. proc perlOpenFile {menu name} {
  555.     set filename [macperlFolder]$name
  556.     if {[file exists $filename]} {
  557.         edit $filename
  558.     } else {
  559.         alertnote "That file doesn't exist yet"
  560.     }
  561. }
  562.  
  563. #############################################################################
  564. # Support procs
  565. #############################################################################
  566.  
  567. #############################################################################
  568. # Prompt the user to enter a string containing command-line args.
  569. #
  570. proc getCmdlineArgs {} {
  571.     global PerlmodeVars
  572.     set oldargs $PerlmodeVars(perlCmdlineArgs)
  573.     if {![catch {prompt "Command-line arguments (if any):" $oldargs} args]} {
  574.         set PerlmodeVars(perlCmdlineArgs) $args
  575.     } else {
  576.         error "getCmdlineArgs: User cancelled"
  577.     }
  578.     return $args
  579. }
  580.  
  581. #############################################################################
  582. # Tell MacPerl to run a script file:
  583. #
  584. proc perlExecuteFile {path {args ""}} {
  585.     global ALPHA macperlPath
  586.     global perlGetOutput perlAutoSwitch perlPromptArgs
  587.     global scriptFile scriptStart
  588.     
  589.     if {[string length $path]} {
  590.         set name [checkRunning MacPerl McPL macperlPath]
  591.         if {[string length $name]} {
  592.         
  593.             set scriptFile $path
  594.             set scriptStart 1            
  595.             
  596. #            set args [readFileForArgs $path]
  597. #            set args ""
  598.             if {$perlPromptArgs} { 
  599.                 append args " [getCmdlineArgs]"
  600.             }
  601.             
  602.             sendCloseWinName MacPerl MacPerl
  603.             if {$perlAutoSwitch} then {switchTo $name} else {watchCursor}
  604.             if {[llength $args]} {
  605.                 perlDoScript2 "MacPerl" $path $args
  606.             } else {
  607.                 dosc -c 'McPL' -t 0 -f $path
  608.             }
  609. # (not sure which choice is better...)
  610. #            if {!$perlAutoSwitch} then {switchTo $ALPHA}
  611.             switchTo $ALPHA
  612. #
  613.             if {![getMacPerlError $scriptFile $scriptStart 0]} {
  614.                 if {$perlGetOutput} then {openPerlOutput}
  615.             }
  616.         } else {
  617.             alertnote "Couldn't run MacPerl"
  618.         }
  619.     } else {
  620.         alertnote "No file specified to execute"
  621.     }
  622. }
  623.  
  624. #############################################################################
  625. # Run a MacPerl script, passed explicitly as a string:
  626. #
  627. # If no "#!/bin/perl" line already exists, one is preprended to the script
  628. # by wrapSelectScript, which also sets $filterHeadLen for use by 
  629. # getMacPerlError.
  630. proc perlExecuteScript {script {args ""}} {
  631.     global macperlPath perlGetOutput perlAutoSwitch perlPromptArgs
  632.     global scriptFile scriptStart filterHeadLen ALPHA
  633.     if {$script != ""} {
  634.         set script [wrapSelectScript $script]
  635.         writeScript $script
  636.         set name [checkRunning MacPerl McPL macperlPath]
  637.         if {[string length $name]} {
  638. #            set args [getScriptArgs $script]
  639. #            set args ""
  640.             if {$perlPromptArgs} { 
  641.                 append args " [getCmdlineArgs]"
  642.             }
  643.             sendCloseWinName MacPerl MacPerl
  644.             if {$perlAutoSwitch} then {switchTo $name} else {watchCursor}
  645.             if {[llength $args]} {
  646.                 perlDoScript2 "MacPerl" [scriptPath] $args
  647.             } else {
  648.                 dosc -c 'McPL' -t 0 -f [scriptPath]    
  649.             }
  650. # (not sure which choice is better...)
  651. #            if {!$perlAutoSwitch} then {switchTo $ALPHA}
  652.             switchTo $ALPHA
  653. #
  654.             if {![getMacPerlError $scriptFile $scriptStart $filterHeadLen]} {
  655.                 if {$perlGetOutput} then {openPerlOutput}
  656.             }
  657.         } else {
  658.             alertnote "Couldn't run MacPerl"
  659.         }
  660.     } else {
  661.             alertnote "No file specified to execute"
  662.     }
  663. }
  664.  
  665. #############################################################################
  666. # Prepare the contents of a disk file for use as a text-filter script. 
  667. # (calls perlTextFilter to actually run the script)
  668. proc perlFileAsFilter {path} {
  669.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  670.     
  671.     regexp {(.*):([^:]*)} $path pathname dirname name
  672.     
  673.     set coreScript [readFile $path]
  674.     if {$coreScript != -1} {
  675.         set script [wrapFilterScript $coreScript]
  676.         set scriptFile $path
  677.         set scriptStart 1
  678.         set perlPrevScript [list "file" $path]
  679.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  680.         enableMenuItem $perlMenu repeatLastFilter 1
  681.         message "Running file \"$name\" as text filter ..."
  682.             
  683.         perlTextFilter $script
  684.     } else {
  685.         set perlPrevScript {}
  686.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  687.         enableMenuItem $perlMenu repeatLastFilter 0
  688.         
  689.         alertnote "Couldn't read the script file : $path"
  690.         return
  691.     }
  692. }
  693.  
  694. #############################################################################
  695. # Prepare the contents of a text window for use as a text-filter script. 
  696. # (calls perlTextFilter to actually run the script)
  697. proc perlBufferAsFilter {wname} {
  698.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  699.  
  700.     regexp {(.*):([^:]*)} $wname pathname dirname name
  701.     
  702.     if {[lsearch [winNames -f] $wname] >= 0} {
  703.         set coreScript [getText -w $wname 0 [maxPos -w $wname]]
  704.         
  705.         # Does it have any text in it?
  706.         if {[string length $coreScript]} {
  707.             set scriptFile $wname
  708.             set scriptStart 1
  709.             set script [wrapFilterScript $coreScript]
  710.             set perlPrevScript [list "buffer" $wname]
  711.             set PerlmodeVars(perlLastFilter) $perlPrevScript 
  712.             enableMenuItem $perlMenu repeatLastFilter 1
  713.             message "Running buffer \"$name\" as text filter ..."
  714.             
  715.             perlTextFilter $script
  716.         }
  717.     } else {
  718.         set perlPrevScript {}
  719.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  720.         enableMenuItem $perlMenu repeatLastFilter 0
  721.  
  722.         alertnote "Couldn't find buffer : $name"
  723.     }
  724. }
  725.  
  726. #############################################################################
  727. # Run a Perl script as a command-line text filter, arranging for a text
  728. # buffer to be attached as standard input.  The calling routine should already
  729. # have processed the script with wrapFilterScript.  This routine actually
  730. # send the script and takes care of writing the input and reading the output 
  731. # files.
  732. proc perlTextFilter {script {args ""}} {
  733.     global macperlPath perlOverwrite perlUsebuffer perlPromptArgs
  734.     global filterHeadLen scriptFile scriptStart ALPHA
  735.  
  736.     set name [checkRunning MacPerl McPL macperlPath]
  737.     if {![string length $name]} {
  738.         alertnote "Couldn't run MacPerl"
  739.         error "Couldn't run MacPerl"
  740.     }
  741.     writeStdin
  742. #    no longer useful, since errors are (hopefully) trapped now.
  743. #    writeStdout
  744.  
  745.     if {$perlPromptArgs} { 
  746.         append args " [getCmdlineArgs]"
  747.     }
  748.     
  749.     sendCloseWinName MacPerl MacPerl
  750.     watchCursor
  751.     perlDoScript2 "MacPerl" [scriptPath] $args [stdinPath]
  752.     switchTo $ALPHA
  753.     if {![getMacPerlError $scriptFile $scriptStart $filterHeadLen]} {
  754.         if {!$perlOverwrite} {new -n {* Perl Output *}}
  755.         if {$perlUsebuffer} {
  756.             pasteStdout 0 [maxPos]
  757.         } else {
  758.             pasteStdout [getPos] [selEnd]
  759.         }
  760.         if {!$perlOverwrite || $perlUseBuffer} {
  761.             catch shrinkWindow
  762.             goto 0
  763.         }
  764.     }
  765. }
  766.  
  767. #############################################################################
  768. # Check the MacPerl output window for error messages.
  769. #
  770. proc getMacPerlError {scriptFile scriptStart offset} {
  771. #    global winModes
  772.     set pat0 {^[ \t]*$}
  773.     set pat1 {^#(.*)$}
  774.     set pat2 {File '[^']+'; Line ([0-9]+)}
  775.     
  776.     # first see if there's any output at all
  777.     set nlines [sendCountLines MacPerl MacPerl]
  778.     if {$nlines == 0} {
  779.         return 0
  780.     }
  781.     set errFound 0
  782.     set errMessage {}
  783.     set lines {}
  784.     
  785. #     # read output window one line at a time
  786. #    set nread 0
  787. #     while {$nread < $nlines} {
  788. #         incr nread
  789. #         set line [sendGetText MacPerl MacPerl $nread]
  790. #[...]
  791. #     }
  792.  
  793.     # read a window-full of MacPerl output (faster, but assumes 
  794.     # error message won't appear at the end of a lot of output).
  795.     set maxLines [expr ($nlines > 40)?40:$nlines]
  796.     set output [sendGetText MacPerl MacPerl 1 $maxLines]
  797.     foreach line [split $output "\r"] {
  798.         if {[regexp $pat2 $line mtch num]} {
  799.             set errFound 1
  800.         } elseif {[regexp $pat1 $line mtch err]} {
  801.             if {$errFound == 0} {
  802.                 set errMessage $err
  803.             }
  804.         } elseif {[regexp $pat0 $line mtch]} {
  805.             break
  806.         }
  807.         append lines "$line\n"
  808.     }
  809.  
  810.     if {$errFound} {
  811.         new -n {* Perl Error Messages *} 
  812.          insertText $lines
  813.         goto 0
  814.         catch {shrinkWindow 1}
  815.         setWinInfo dirty 0
  816.         setWinInfo read-only 1
  817.         
  818.         # Now get the line number associated with the first error
  819.         regexp $pat2 $lines mtch num
  820.         # Convert it to the line number in the original file
  821.         set lineNum [expr $num + $scriptStart - $offset - 1]
  822.         # Bring up the script file and highlight the flagged line
  823.         catch {gotoFileLine $scriptFile $lineNum} fname    
  824.         # ... and leave an informative error message
  825.         if {$errMessage != {}} {
  826.             message "$errMessage at Line $lineNum"            
  827.         } else {
  828.             message "MacPerl flagged an error at Line $lineNum"    
  829.         }
  830.         return 1
  831.         
  832.     } else {
  833.         return 0
  834.     }
  835. }
  836.  
  837. #############################################################################
  838. #  Highlight (select) a particular line in the designated file, opening the
  839. #  file if necessary.  Returns the full name of the buffer containing the
  840. #  opened file.
  841. #
  842. proc gotoFileLine {fname line} {
  843.     if {[expr {[lsearch [winNames -f] "*$fname"] >= 0}]} {
  844.         bringToFront $fname
  845.     } elseif {[expr {[lsearch [winNames] "*$fname"] >= 0}]} {
  846.         bringToFront $fname
  847.     } elseif {[file exists $fname]} {
  848.         edit $fname
  849.     } else {
  850.         alertnote "File \" $fname \" not found." ; return
  851.     }
  852.     set pos [rowColToPos $line 0]
  853.     select [lineStart $pos] [nextLineStart $pos]
  854.     return [lindex [winNames -f] 0]
  855. }
  856.  
  857. #############################################################################
  858. #  Take a Perl script and add commands to take the file STDIN as standard
  859. #  input and STDOUT as standard output.  This allows scripts written as
  860. #  Unix command-line filters to be used in the (non-MPW) Mac environment as
  861. #  text filters.
  862. #
  863. #  If there's already a #! line in the script, then the new commands
  864. #  are added after that line.  If there was no #! line in the first place,
  865. #  one is added, in case MacPerl is set up to require it (can't hurt...) 
  866. #
  867. #  $filterHeadLen counts the number of lines we add to the top of the
  868. #  original script, so that we can allow for it in interpreting error
  869. #  messages issued by MacPerl.
  870. #
  871. proc wrapFilterScript {coreScript} {
  872.     global filterHeadLen
  873.  
  874.     if {[regexp -indices {(#![     !-~]*)} $coreScript allofit cmdln]} {
  875.         set endPos [lindex $cmdln 1]
  876.         set filterHead [string range $coreScript 0 [expr $endPos+1]]
  877.         set coreScript [string range $coreScript [expr $endPos+2] end]
  878.         set filterHeadLen 0
  879.     } else {
  880.         set filterHead "#!/bin/perl\n"
  881.         set filterHeadLen 1
  882.     }
  883.     append filterHead "\$macperlDir = \"[macperlFolder]\" ;\n"
  884. # Pass the input file as a command-line file arg, instead.
  885. #    append filterHead "open(STDIN, \"<[stdinPath]\" ) ;\n"
  886.     append filterHead "open(STDOUT, \">[stdoutPath]\" ) ;\n"
  887.     append filterHead "select(STDOUT) ;\n\n"
  888.     incr filterHeadLen 6
  889.     
  890.     set filterTail "\nclose STDIN ;\nclose STDOUT ;\n"
  891.         
  892.     set script $filterHead
  893.     append script $coreScript
  894.     append script $filterTail
  895.     
  896.     writeScript $script
  897.     return $script
  898. }        
  899.  
  900. #############################################################################
  901. #  Add a #!/bin/perl line to the script if it doesn't contain one already.
  902. #  (MacPerl puts up dialog if this line is missing when it expects it,
  903. #  hanging the DoScript and leaving us stuck.)
  904. #
  905. proc wrapSelectScript {coreScript} {
  906.     global filterHeadLen
  907.  
  908.     if {![regexp -indices {(#![     !-~]*)} $coreScript allofit cmdln]} {
  909.         set script "#!/bin/perl\n"
  910.         append script $coreScript
  911.         set filterHeadLen 1
  912.     } else {
  913.         set script $coreScript
  914.         set filterHeadLen 0
  915.     }
  916.     
  917.     writeScript $script
  918.     return $script
  919. }        
  920.  
  921. #############################################################################
  922. #  Paste the text of the file STDOUT in place of the current selection.
  923. #
  924. proc pasteStdout {from to} {
  925.     set result [readFile [stdoutPath]]
  926.     if {$result != -1} {
  927.         deleteText $from $to
  928.         insertText $result
  929.         catch shrinkWindow
  930.         goto 0
  931.     } else {
  932.         alertnote "Couldn't find the output file : STDOUT"
  933.     }
  934. }    
  935. #        replaceText [getPos] [selEnd] $result
  936.  
  937. #############################################################################
  938. #  Extend the current selection to encompass complete lines.  If the 
  939. #  'applyToBuffer' flag is checked, then the entire buffer is selected.
  940. #
  941. proc completeSelection {} {
  942.     global perlUsebuffer
  943.     if {$perlUsebuffer} {
  944.         set start 0
  945.         set end [maxPos]
  946.     } else {
  947.         set start [lineStart [getPos]]
  948.         set end [nextLineStart [expr [selEnd]-1]]
  949.     }
  950.     if {$end == $start} {set end [nextLineStart [selEnd]]}
  951.     return [list $start $end]
  952. }
  953.  
  954. #############################################################################
  955. #  writeStdin: Extend the selection, as appropriate, and write it to the 
  956. #     STDIN file in the MacPerl directory.
  957. #  writeStdout: Write the extended selection to the STDOUT file.  This will
  958. #      then be the default output in case MacPerl hangs. 
  959. #  writeScript: Write the SCRIPT file in the MacPerl directory.  MacPerl will
  960. #     read the script from this file. 
  961. #
  962. proc writeStdin {} {
  963.     set res [completeSelection]
  964.     set tmpfid [open [stdinPath] "w+"]
  965.     puts $tmpfid [eval getText $res]
  966.     close $tmpfid
  967. }
  968.  
  969. # This should be unnecessary now that we're watching for MacPerl errors...
  970. proc writeStdout {} {
  971.     set res [completeSelection]
  972.     set tmpfid [open [stdoutPath] "w+"]
  973.     puts $tmpfid [eval getText $res]
  974.     close $tmpfid
  975. }
  976.  
  977. # This will hopefully be unnecessary with the next release of MacPerl...
  978. proc writeScript {script} {
  979.     set tmpfid [open [scriptPath] "w+"]
  980.     puts $tmpfid $script 
  981.     close $tmpfid
  982. }
  983.  
  984. #############################################################################
  985. #  Read and return the complete contents of the specified file.
  986. #
  987. proc readFile {fileName} {
  988.     if {[file exists $fileName] && [file readable $fileName]} {
  989.        set fileid [open $fileName "r"]
  990.        set contents ""
  991.        while {[gets $fileid nextLine] != -1} {
  992.           append contents $nextLine "\n"
  993.        }
  994.        close $fileid
  995.        return $contents
  996.     } else {
  997.        return -1
  998.     }
  999. }
  1000.  
  1001. #############################################################################
  1002. #  Scan a file for a command line, and return the arguments found.
  1003. #
  1004. proc readFileForArgs {fileName} {
  1005.     if {[file exists $fileName] && [file readable $fileName]} {
  1006.         set fileid [open $fileName "r"]
  1007.         set contents ""
  1008.         while {[gets $fileid nextLine] != -1} {
  1009.             if {[regexp {^[ \t]*#![^ \t]+(.*)$} $nextLine mtch args]} {
  1010.                 close $fileid
  1011.                 set args [string trim $args]
  1012.                 return $args
  1013.             }
  1014.         }
  1015.         close $fileid
  1016.         return ""
  1017.     } else {
  1018.         return -1
  1019.     }
  1020. }
  1021.  
  1022. #############################################################################
  1023. #  Scan a script for a command line, and return the arguments found.
  1024. #
  1025. proc getScriptArgs {script} {
  1026.     set lines [split $script "\r"]
  1027.     foreach line $lines {
  1028.         if {[regexp {^[ \t]*#![^ \t]+(.*)$} $line mtch args]} {
  1029.             set args [string trim $args]
  1030.             return $args
  1031.         }
  1032.     }
  1033.     return ""
  1034. }
  1035.  
  1036. #############################################################################
  1037. # Read the MacPerl output window and load the contents, if any, into
  1038. # a new Alpha window. 
  1039. #
  1040. proc openPerlOutput {} {
  1041.     set output [sendGetText MacPerl MacPerl]
  1042.     if {[string length $output]} {
  1043.         new -n {* MacPerl Output *}
  1044.         insertText $output
  1045.         catch {shrinkWindow 1}
  1046.         goto 0
  1047.     }
  1048. }
  1049.  
  1050. #############################################################################
  1051. # General Apple Event routines
  1052. # (These should work with any application that supports the appropriate events)
  1053. #
  1054.  
  1055. # Get the name that Alpha is running under, so we can switch back here 
  1056. # explicitly when needed.
  1057. foreach p [processes] {
  1058.     if {[lindex $p 1] == "ALFA"} {
  1059.         set ALPHA [lindex $p 0]
  1060.         break
  1061.     }
  1062. }
  1063.  
  1064. # AEBuild utility functions
  1065. proc curlyq {str} {
  1066.     return "\“$str\”"
  1067. }
  1068. proc AEAbsPos {posName} {
  1069. # (would like to be able to use 'first' and 'last' as well, but haven't yet
  1070. # figured out the correct AEBuild syntax.  "seld:abso('firs')" doesn't work.)
  1071.     if {$posName > 0} {
  1072.         return "form:indx, seld:long($posName)"
  1073.     } else {
  1074.         error "AEAbsPos: bad argument"
  1075.     }
  1076. }
  1077. proc AEName {name} {
  1078.     return "form:'name', seld:[curlyq $name]"
  1079. }
  1080. proc AEWinByName {name} {
  1081.     return "obj{want:type('cwin'), from:'null'(), [AEName $name] } "
  1082. }
  1083. proc AEWinByPos {absPos} {
  1084.     return "obj{want:type('cwin'), from:'null'(), [AEAbsPos $absPos] } "
  1085. }
  1086. proc AELineRange {absPos1 absPos2} {
  1087.     set lineObj1 "obj{ want:type('clin'), from:'ccnt'(), [AEAbsPos $absPos1] }"
  1088.     set lineObj2 "obj{ want:type('clin'), from:'ccnt'(), [AEAbsPos $absPos2] }"
  1089.     return "form:'rang', seld:rang{star:$lineObj1, stop:$lineObj2 } "
  1090. }
  1091.  
  1092. # Quit an application.
  1093. proc sendQuitEvent {appname} {
  1094.     AEBuild $appname "aevt" "quit" 
  1095. }
  1096.  
  1097. # Close one of an application's windows, designated by number.
  1098. proc sendCloseWinNum {appname num} {
  1099.     AEBuild $appname "core" "clos" "----" [AEWinByPos $num]
  1100. }
  1101.  
  1102. # Close one of an application's windows, designated by name.
  1103. proc sendCloseWinName {appname name} {
  1104.     AEBuild $appname "core" "clos" "----" [AEWinByName $name]
  1105. }
  1106.  
  1107. # Obtain the number of lines in one of an application's
  1108. # windows, designated by name.
  1109. proc sendCountLines {appname name} {
  1110.     set winObj [AEWinByName $name]
  1111.     set res [AEBuild -r $appname "core" "cnte" "----" $winObj kocl type('clin')]    
  1112.     if {[regexp {:(.*)\}} $res allofit nlines]} {
  1113.         return $nlines
  1114.     } else {
  1115.         return 0
  1116.     }
  1117. }
  1118.  
  1119. # Get a selected range of lines from one of an application's
  1120. # windows, designated by name.  If $last is missing, then a single
  1121. # line is returned; if both $first and $last are missing, then
  1122. # the complete window contents are returned.
  1123. proc sendGetText {appname name {first {missing}} {last {missing}}} {
  1124.     global ALPHA
  1125.     set winObj [AEWinByName $name]
  1126.     if {$first != "missing"} {
  1127.         if {$last != "missing"} {
  1128.             set rangDesc [AELineRange $first $last]
  1129.         } else {
  1130.             set rangDesc [AEAbsPos $first]
  1131.         }
  1132.         set objDesc "obj{want:type('clin'), from:$winObj, $rangDesc }"
  1133.     } else {
  1134.         set objDesc "obj{want:type('ctxt'), from:$winObj, form:'indx', seld:abso('all') }"
  1135.     }
  1136.     set res [AEBuild -r $appname "core" "getd" "----" $objDesc]    
  1137.     if {![regexp {“.*”} $res text]} { set text {} }
  1138.     return [string trim $text {“”}]
  1139. }
  1140.  
  1141. # Send a DoScript event, optionally including the special flags recognized
  1142. # by MacPerl.  (debugged, but not currently used)
  1143. proc perlDoScript {appname script {flags {}}} {
  1144.     if {$script != ""} {
  1145.         append descriptor " ---- {[curlyq $script]}"
  1146.     } else {
  1147.         error "perlDoScript: missing script argument"
  1148.     }        
  1149.     set usrf {}
  1150.     if {[lsearch -exact $flags "extract"] >= 0} {
  1151.         append usrf { "EXTR" 'true'}
  1152.     } elseif {[lsearch -exact $flags "noextract"] >= 0} {
  1153.         append usrf { "EXTR" 'fals'}
  1154.     }        
  1155.     if {[lsearch -exact $flags "debug"] >= 0} {
  1156.         append usrf { "DEBG" 'true'}
  1157.     } elseif {[lsearch -exact $flags "nodebug"] >= 0} {
  1158.         append usrf { "DEBG" 'fals'}
  1159.     }        
  1160.     if {[lsearch -exact $flags "preprocess"] >= 0} {
  1161.         append usrf { "PREP" 'true'}
  1162.     } elseif {[lsearch -exact $flags "nopreprocess"] >= 0} {
  1163.         append usrf { "PREP" 'fals'}
  1164.     }        
  1165.     eval "AEBuild -r \"$appname\" misc dosc $descriptor $usrf"
  1166. }
  1167.  
  1168. proc perlDoScript2 {appname fname {args {}} {fileArg {}}} {
  1169.     set nargs 0
  1170.     if {$fname != ""} {
  1171.         set argv "\[[curlyq $fname]"
  1172.          foreach item [split [join $args " "] " "] {
  1173.             set item [string trim $item]
  1174.             if {[string length $item]} {
  1175.                 append argv ", [curlyq $item]"
  1176.                 incr nargs
  1177.             }
  1178.         }
  1179.         if {[string length $fileArg]} {
  1180. #             if {$nargs} {
  1181. #                 append argv ", [curlyq --]"
  1182. #             }
  1183.             append argv ", [curlyq $fileArg]"
  1184.         }
  1185.         append argv "]"
  1186.     set reply [eval "AEBuild -r \"$appname\" misc dosc \"----\" [list $argv]"]
  1187. #    alertnote $reply
  1188.     }
  1189. }
  1190.  
  1191. ##############################################################################
  1192. # Automatic subroutine marking for Perl mode in Alpha 5.85
  1193. #
  1194. # (code stolen shamelessly from 'tclMarkFile' in 'tcl.tcl')
  1195. #
  1196. proc PerlMarkFile {} {
  1197.     set end [maxPos]
  1198.     set pos 0
  1199.     set l {}
  1200.     while {![catch {search -f 1 -r 1 -m 0 -i 0 {^sub} $pos} res]} {
  1201.         set start [lindex $res 0]
  1202.         set end [nextLineStart $start]
  1203.         set text [lindex [getText $start $end] 1]
  1204.         set pos $end
  1205.         set inds($text) [lineStart [expr $start - 1]]
  1206.     }
  1207.  
  1208.     if {[info exists inds]} {
  1209.         foreach f [lsort [array names inds]] {
  1210.             set next [nextLineStart $inds($f)]
  1211.             setNamedMark $f $inds($f) $next $next
  1212.         }
  1213.     }
  1214. }
  1215.  
  1216. proc dummyPerl {} {
  1217. }
  1218.  
  1219. ##############################################################################
  1220. # Perl mode definitions  (for Alpha 5.90)
  1221. #
  1222. lappend modes Perl
  1223. set dummyProc(Perl)                dummyPerl
  1224. set modeMenus(Perl)                 { perlMenu }
  1225. lappend modeSuffixes            {*.pl} { set winMode Perl }
  1226. newModeVar Perl elecRBrace    {0} 1
  1227. newModeVar Perl elecLBrace    {1} 1
  1228. newModeVar Perl electricSemi    {0} 1
  1229. newModeVar Perl wordBreak        {(\$)?[a-zA-Z0-9_]+} 0
  1230. newModeVar Perl prefixString    {# } 0
  1231. newModeVar Perl wordWrap        {0} 1
  1232. newModeVar Perl funcExpr        {^sub *([+-a-zA-Z0-9]+)} 0
  1233. newModeVar Perl wordBreakPreface        {[^a-zA-Z0-9_\$]} 0
  1234. newModeVar Perl optionIsMeta    {1} 1
  1235.  
  1236. set perlKeywords {
  1237. accept alarm atan2 bind binmode caller chdir chmod chop chown chroot 
  1238. close closedir connect continue cos crypt dbmclose dbmopen defined 
  1239. delete die do dump each else elsif eof eval exec exit exp fcntl fileno 
  1240. flock for foreach fork getc getlogin getpeername getpgrp getppid 
  1241. getpriority getgrnam gethostbyname getnetbyname getprotobyname getpwuid 
  1242. getgrgid getservbyname gethostbyaddr getnetbyaddr getprotobynumber 
  1243. getservbyport getpwent getgrent gethostent getnetent getprotoent 
  1244. getservent setpwent setgrent sethostent setnetent setprotoent setservent 
  1245. endpwent endgrent endhostent endnetent endprotoent endservent 
  1246. getsockname getsockopt gmtime goto grep hex if index int ioctl join keys 
  1247. kill last length link listen local localtime log lstat lstat mkdir 
  1248. msgctl msgget msgsnd msgrcv next oct open opendir ord pack pipe pop 
  1249. print print printf printf push q qq qx rand read readdir readlink recv 
  1250. redo rename require reset return reverse rewinddir rindex rindex rmdir 
  1251. scalar seek seekdir select semctl semget semop send setpgrp setpriority 
  1252. setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep 
  1253. socket socketpair sort splice split sprintf sqrt srand stat study sub 
  1254. substr symlink syscall sysread system syswrite tell telldir time times 
  1255. tr truncate umask undef unless unlink unpack unshift until utime values 
  1256. vec wait waitpid wantarray warn while write eq ne cmp lt gt le ge @_ $_ $.  
  1257. $/ $, $" $\\ $\# $% $= $- $~ $^ $| $$ $? $& $` $' $+ $* $0 $1 $2 $3 $4 $5 
  1258. $6 $7 $8 $9 $[ $] $; $! $@ $< $> $( $) $: $^D $^F $^I $^P $^T $^W $^X 
  1259. $ARGV @ARGV @INC %INC $ENV $SIG
  1260. }
  1261. regModeKeywords -e {#} -c red -k blue Perl $perlKeywords
  1262. unset perlKeywords
  1263.                 
  1264. ##############################################################################
  1265. # Make sure Perl-mode is installed correctly if this file is loaded
  1266. # after the mode-variables menus have already been built.
  1267. #
  1268. set modes [lsort $modes]
  1269. buildFlagsVars
  1270.  
  1271. ##############################################################################
  1272.